package com.senmiao.ssm.aspect;

import com.senmiao.ssm.aspect.annotation.DoDeleteLog;
import com.senmiao.ssm.aspect.annotation.DoInsertLog;
import com.senmiao.ssm.aspect.annotation.DoQueryLog;
import com.senmiao.ssm.aspect.annotation.DoUpdateEmployeeLog;
import com.senmiao.ssm.constants.MyConstants;
import com.senmiao.ssm.entity.Employee;
import com.senmiao.ssm.pojo.AdminShiro;
import com.senmiao.ssm.service.DoLogService;
import com.senmiao.ssm.utils.IPHelper;
import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.List;

/**
 * 日志切面类
 */
@Aspect
@Component
public class DoLogAspect {

    @Autowired
    private DoLogService doLogService;

    /**
     * 登录成功进行日志记录
     *
     * @param joinPoint
     */
    @AfterReturning(pointcut = "@annotation(com.senmiao.ssm.aspect.annotation.DoLoginLog)")
    public void loginSuccess(JoinPoint joinPoint) {
        System.out.println("登录成功，记录日志");
        Object[] args = joinPoint.getArgs();
        String account = args[0] + "";
        System.out.println(account);
        // 调用日志服务类保存到数据库
        doLogService.saveLoginLog(account, IPHelper.getIpAddr(), MyConstants.LOGIN_SUCCESS);
    }

    /**
     * 登录失败进行日志记录
     *
     * @param joinPoint
     */
    @AfterThrowing(pointcut = "@annotation(com.senmiao.ssm.aspect.annotation.DoLoginLog)")
    public void loginFailed(JoinPoint joinPoint) {
        System.out.println("登录失败，记录日志");
        Object[] args = joinPoint.getArgs();
        String account = args[0] + "";
        System.out.println(account);
        // 调用日志服务类保存到数据库
        doLogService.saveLoginLog(account, IPHelper.getIpAddr(), MyConstants.LOGIN_FAILED);
    }

    /**
     * 登出操作日志记录
     *
     * @param joinPoint
     */
    @Before("@annotation(com.senmiao.ssm.aspect.annotation.DoLogoutLog)")
    public void logoutLog(JoinPoint joinPoint) {
        System.out.println("登出");
        // 获取登录用户的id
        Object principal = SecurityUtils.getSubject().getPrincipal();
        System.out.println("principal = " + principal);
        if (principal != null) {
            AdminShiro adminShiro = (AdminShiro) principal;
            Integer adminId = adminShiro.getId();
            doLogService.saveLogoutLog(adminId, IPHelper.getIpAddr());
        }
    }

    /**
     * 插入操作日志记录
     *
     * @param joinPoint
     */
    @AfterReturning(pointcut = "@annotation(com.senmiao.ssm.aspect.annotation.DoInsertLog)")
    public void insertLog(JoinPoint joinPoint) {
        // 拿表名
        String tableName = getMethod(joinPoint).getAnnotation(DoInsertLog.class).tableName();
        // 进行操作的管理员id
        Integer adminId = getAdminId();
        if (adminId == null) {
            return;
        }
        doLogService.insertLog(adminId,tableName);

    }

    /**
     * 删除操作日志记录
     *
     * @param joinPoint
     */
    @AfterReturning(pointcut = "@annotation(com.senmiao.ssm.aspect.annotation.DoDeleteLog)")
    public void deleteLog(JoinPoint joinPoint) {
        System.out.println("删除操作，进行日志记录");
        // 拿表名
        String tableName = getMethod(joinPoint).getAnnotation(DoDeleteLog.class).tableName();
        // 进行操作的管理员id
        Integer adminId = getAdminId();
        if (adminId == null) return;
        // 拿操作的表id
        List<Integer> employeeIds = (List<Integer>) joinPoint.getArgs()[0];
        // 调用日志服务类
        doLogService.saveDeleteLog(employeeIds, tableName, adminId, IPHelper.getIpAddr());
    }

    /**
     * 更新操作日志记录
     *
     * @param proceedingJoinPoint
     */
    @Around(value = "@annotation(com.senmiao.ssm.aspect.annotation.DoUpdateEmployeeLog)")
    public Object updateLog(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        // 表名
        String tableName = getMethod(proceedingJoinPoint).getAnnotation(DoUpdateEmployeeLog.class).tableName();
        // 进行操作的管理员id
        Integer adminId = getAdminId();
        // 拿到记录的id
        Integer recordId = (Integer) proceedingJoinPoint.getArgs()[0];
        // 拿到修改前的记录
        Employee pre = doLogService.getEmployeeById(recordId);
        // 执行修改操作
        Object result = proceedingJoinPoint.proceed();
        // 拿到修改后的记录
        Employee after = doLogService.getEmployeeById(recordId);
        // 将有修改前和修改后的实体对象进行对比，并记入日志表
        if (adminId != null){
            doLogService.updateLog(recordId, adminId, tableName, pre, after);
        }
        return result;
    }

    /**
     * 角色权限更改的日志记录
     *
     * @param proceedingJoinPoint
     * @return
     */
    @Around("@annotation(com.senmiao.ssm.aspect.annotation.DoAuthorizeLog)")
    public Object authorizeLog(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        // 获取进行操作的管理员id
        Integer adminId = getAdminId();
        // 拿到角色权限变更前的权限列表
        Integer roleId = (Integer) proceedingJoinPoint.getArgs()[0];
        List<Integer> permissionsIdsOfRolePre = doLogService.getPermissionIdsOfRole(roleId);
        // 权限变更
        Object result = proceedingJoinPoint.proceed();
        // 拿到权限变更后的权限列表
        List<Integer> permissionsIdsOfRoleAfter = doLogService.getPermissionIdsOfRole(roleId);
        // 进行日志记录
        if (adminId != null) {
            doLogService.authorizeLog(adminId, roleId, permissionsIdsOfRolePre, permissionsIdsOfRoleAfter);
        }
        return result;
    }

    /**
     * 查看操作的日志记录
     * @param joinPoint
     */
    @Before("@annotation(com.senmiao.ssm.aspect.annotation.DoQueryLog)")
    public void queryLog(JoinPoint joinPoint){
        Integer adminId = getAdminId();
        String tableName = getMethod(joinPoint).getAnnotation(DoQueryLog.class).tableName();
        if (adminId == null){
            return;
        }
        doLogService.queryLog(adminId,tableName);
    }

    /**
     * 修改管理员的角色的日志记录
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around("@annotation(com.senmiao.ssm.aspect.annotation.DoUpdateAdminRoleLog)")
    public Object changeAdminRoleLog(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        // 获取进行操作的管理员id
        Integer adminId = getAdminId();
        // 拿到修改前的角色信息
        Integer adminIdUpdate = (Integer) proceedingJoinPoint.getArgs()[0];
        Integer roleIdPre = doLogService.getRoleIdOfAdmin(adminIdUpdate);
        // 权限变更
        Object result = proceedingJoinPoint.proceed();
        // 拿到修改后的角色信息
        Integer roleIdAfter = doLogService.getRoleIdOfAdmin(adminIdUpdate);
        // 进行日志记录
        if (adminId != null) {
            doLogService.changeAdminRoleLog(adminId,adminIdUpdate,roleIdPre,roleIdAfter);
        }
        return result;
    }

    /**
     * 通过MethodSignature，拿到方法上的注解
     *
     * @param joinPoint
     */
    private Method getMethod(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        return signature.getMethod();
    }

    /**
     * 获取当前登录的管理员id
     *
     * @return
     */
    private Integer getAdminId() {
        Object principal = SecurityUtils.getSubject().getPrincipal();
        if (principal == null) {
            return null;
        }
        AdminShiro adminShiro = (AdminShiro) principal;
        return adminShiro.getId();
    }

}